<?php
namespace Hilaoyu\Utils;

use Hilaoyu\Utils\Traits\ErrorsTrait;
use phpseclib3\Net\SFTP;
use phpseclib3\Net\SSH2;

/**
 * Created by laoyu.
 * User: hilaoyu@qq.com
 */

/**
 * Class UtilSsh
 * @package Hilaoyu\Utils
 * @property UtilProxyClient $proxy
 */
class UtilSsh {
    use ErrorsTrait;
    protected $proxy=null;


    /**
     * @param $host
     * @param string $username
     * @param string $password
     * @param int $port
     * @param int $timeout
     * @return SSH2|null
     */
    public function sshConnect($host,$username='',$password='',$port=22,$timeout=10){

        try{
            if(false === $this->proxy){
                return null;
            }
            if($this->proxy){
                if(! $fsock = $this->proxy->proxyTo($host,$port)->getFsock()){
                    $this->setError($this->proxy->getError());
                    return null;
                }
                $ssh = new SSH2($fsock);
            }else{
                $ssh =  new SSH2($host,$port,$timeout);
            }
            if(!$ssh->login($username,$password)){
                return null;
            }
            return $ssh;
        }catch (\Exception $exception){
            $this->setError($exception->getMessage());
        }
        return null;


    }

    /**
     * @param $host
     * @param string $username
     * @param string $password
     * @param int $port
     * @param int $timeout
     * @return SFTP|null
     */
    public function sfpConnect($host,$username='',$password='',$port=22,$timeout=10){

        try{
            if(false === $this->proxy){
                return null;
            }
            if($this->proxy){
                if(! $fsock = $this->proxy->proxyTo($host,$port)->getFsock()){
                    $this->setError($this->proxy->getError());
                    return null;
                }
                $sftp = new SFTP($fsock);
            }else{
                $sftp =  new SFTP($host,$port,$timeout);
            }
            if(!$sftp->login($username,$password)){
                return null;
            }

            return $sftp;
        }catch (\Exception $exception){
            $this->setError($exception->getMessage());
        }
        return null;
    }

    /**
     * 没调试通
     * @param string $host
     * @param int $port
     * @param string $username
     * @param string $password
     * @param int $timeout
     * @return $this
     */
    public function setProxyHttp(string $host,int $port=80,string $username='',string $password='',int $timeout=30){

        $proxy = UtilProxyClient::makeHttpProxy($host,$port,$username,$password,$timeout);
        if($proxy->getFsock()){
            $this->proxy = $proxy;
        }else{
            $this->setError($proxy->getError());
            $this->proxy = false;
        }
        return $this;

    }


    public function setProxySockes(string $host,int $port=80,string $username='',string $password='',int $timeout=30){

        $proxy = UtilProxyClient::makeSocks5Proxy($host,$port,$username,$password,$timeout);
        if($proxy->getFsock()){
            $this->proxy = $proxy;
        }else{
            $this->proxy = false;
            $this->setError($proxy->getError());
        }
        return $this;

    }


    public function disconnect(){
        if($this->proxy){
            try{
                $this->proxy->disconnect();

            }catch (\Exception $exception){

            }
        }
    }

    public function __destruct(){
        $this->disconnect();
    }

    /**
     * Execute Command
     *
     * If $callback is set to false then \phpseclib3\Net\SSH2::get_channel_packet(self::CHANNEL_EXEC) will need to be called manually.
     * In all likelihood, this is not a feature you want to be taking advantage of.
     *
     * @param SSH2|SFTP $ssh
     * @param string $command
     * @param callable $callback
     * @return string|bool
     * @psalm-return ($callback is callable ? bool : string|bool)
     * @throws \RuntimeException on connection error
     */
    static public function exec(&$ssh,$command, $callback = null)
    {
        $result=$ssh->exec($command,$callback);
        $ssh->reset(SSH2::CHANNEL_EXEC);

        return $result;
    }


}
